/**
* \file main.c
* \brief main server file
* \author Goundy
* \version 0.1
* \date 13/10/2007
*/


#include "header.h"
#include "globals.h"
#include "mtime.h"
#include "critical.h"
#include "sig.h"
#include "net.h"
#include "config.h"
#include "db.h"
#include "hashtables.h"
#include "threads.h"
#include "modules.h"
#include "linkedlists.h"
#include "users.h"
#include "channels.h"
#include "server.h"

int daemonize = 1;
const char* fconfig = "server.conf";

/**
* \fn int main (int argc, char* argv)
* \brief server entry function
* \return 0 - normal exit -1 - On error
*/
int main (int argc, char *argv[])
{

 int listensocket,
     acceptsocket,
#ifdef USE_SSL
	 ssllistensocket,
	 sslacceptsocket,
#endif
     gard,
	 opt;
 struct sockaddr_in *serversin,
    	            clientsin;
#ifdef USE_SSL
 struct sockaddr_in	*sslserversin,
					sslclientsin;
#endif
 size_t clilen;
 Peer *peer;

	ServRestartFlag = 0;
	ServCloseFlag = 0;

#ifdef DEBUG_MODE
	gard = set_mtrace();
	if (gard != 0)
		fprintf (stderr, "Couldn't set mtrace\n");
#endif

	/* init time */

	gard = (int)time_now ();
	if (gard == -1){
		fprintf (stderr, "Clock error !!\n");
		return gard;
	}
	printf ("Server started at ");
	time_print_current(starttime);

	while ((opt = getopt(argc, argv, "dhc:r")) != -1)
	{
		switch (opt)
		{
			case 'd': /*debug (don't demonize)*/
				daemonize = 0;
				printf ("debug mode\n");
				break;
			case 'c': /*use config file*/
				fconfig = optarg;
				printf ("new conf file: %s\n", fconfig);
				break;
			case 'h': /*halte*/
				printf ("halting...\n");
				gard = server_halt();
				if (gard != 0){
					fprintf (stderr, "Unable to halt aures. Is it already running?\n");
					return gard;
				}
				fprintf (stdout, "server halted\n");
				return 0;
				break;
			case 'r': /*restart*/
				printf ("restarting...\n");
				gard = server_restart();
				if (gard != 0){
					fprintf (stderr, "Unable to restart aures. Is it already running?\n");
					return gard;
				}
				fprintf (stdout, "server restarted\n");
				return 0;
				break;
			case 'b': /*create database*/
				db_create();
				break;
			case 'e': /*export database*/
				db_export();
			case 'i': /*import database*/
				db_import("path_to_export/export");
			case '?':
				break;
			default:
				break;
		}
	}

	if (geteuid() == 0)
		printf ("I'm running as root\n");
	else
		printf ("I'm not running as root\n");

	/*daemonization*/
	if (daemonize){
		int i = fork();
		if (i < 0){
			fprintf (stderr, "Critical: fork() error\n");
			return -1;
		}
		if (i > 0) exit(0); /*parent exits*/

		setsid();
		for (i=getdtablesize(); i>=0; i--)
			close (i);

		i = open ("/dev/null", O_RDWR);
		if (i == -1){
			fprintf (stderr, "Unable to open /dev/null\n");
			return -1;
		}
		dup (i); /*stdout*/
		dup (i); /*stderr*/
		umask(027);
		chdir("~/");
	}

	gard = server_lock ();
	if (gard == -1){
		fprintf (stderr, "an instance of aures is already running\n");
		return gard;
	}
	else
	{
		fprintf (stdout, "Running pid %d\n", gard);
	}

	while(!ServCloseFlag){
		printf ("gonna ahead\n");
		ServRestartFlag = 0;
		/* load config */
		gard = config_load (fconfig);
			if (gard == -1)
			{
				printf ("error loading configuration\n");/*<----------------------------------------------------*/
				return -1;
			}
		config_print();
		/* init mutex */
	
		gard = mutex_create_all ();
			if (gard == -1)
			{
				printf ("init mutex error\n");/*<------------------------------------------------------*/
				return -1;
			}
	
		/* init signals */
	
		gard = sig_init ();
			if (gard == -1)
			{
				printf ("init signals error\n");/*<----------------------------------------------------*/
				return -1;
			}
	
	
		/* init network */
	
		serversin = NetInit (AF_INET, NetworkConf.Port);
			if (serversin == NULL)
			{
				printf ("init network error\n");/*<----------------------------------------------------*/
				return -1;
			}
	#ifdef USE_SSL
		sslserversin = NetInit (AF_INET, NetworkConf.SslPort);
			if (sslserversin == NULL)
			{
				printf ("ssl init network error\n");/*<----------------------------------------------------*/
				return -1;
			}
	#endif
		listensocket = serv_socket_create (AF_INET, SOCK_STREAM, serversin);
			if (listensocket == -1)
			{
				printf ("init socket error\n");/*<----------------------------------------------------*/
				return -1;
			}
	
	#ifdef USE_SSL
		ssllistensocket = serv_socket_ssl_create (AF_INET, SOCK_STREAM, sslserversin);
			if (ssllistensocket == -1)
			{
				printf ("init socket error\n");/*<----------------------------------------------------*/
				return -1;
			}
	#endif
		/* init db */
	
		/*gard = db_connect (MysqlConf.Host, MysqlConf.User, MysqlConf.Pwd, MysqlConf.DB, MysqlConf.Port, 0);
			if (gard == -1){
				printf ("error connecting to database\n");
				return -1;
			}*/
	
		/* create and init hashtables */
	
		printf ("initialize users hash table ...");
		gard = client_init_hashtable ();
			if (gard < 0) return -1;
		printf ("done\n");
	
		printf ("initialize channels hash table ...");
		gard = chan_init_hashtable ();
			if (gard < 0) return -1;
		printf ("done\n");
	
		/* create linked lists */
		modules_list = List_New();
		if (modules_list == NULL)
			return -1;
		threads_list = List_New();
		if (threads_list == NULL)
			return -1;
		auth_list = List_New();
		if (auth_list == NULL)
			return -1;
	
	
		/*
			Load all modules (commands and hooks)
		*/
			printf ("loading modules... \n");
			module_load_all ();
			printf ("done\n");
		/* create threads */
	
		printf ("creating threads... ");
		gard = thread_create_all ();
			if (gard != 0)
			{
				printf ("couldn't create threads\n");/*<------------------------------------------*/
				return -1;
			}
		printf ("done\n");
		/* listening */
	
	
	
		clilen = sizeof (clientsin);
	
		while ((ServRestartFlag == 0) && (ServCloseFlag == 0))
		{
			acceptsocket = accept (listensocket, (struct sockaddr*)&clientsin, &clilen);

			if (!ServRestartFlag && !ServCloseFlag){
				peer = peer_new (clientsin, acceptsocket);
				if (peer != NULL){
					MUTEX_LOCK (auth_mutex);
					List_PushTail (auth_list, LIST_GENERIC(peer));
					MUTEX_UNLOCK (auth_mutex);
				}
				acceptsocket = -1;
			}
		}

		mutex_del_all ();
		close (listensocket);
	#ifdef USE_SSL
		close (ssllistensocket);
	#endif
		/*shutdown (listensocket,)*/

	}/*while(!ServCloseFlag)*/

	server_unlock();

#ifdef DEBUG_MODE
	unset_mtrace();
#endif

 return 0;
}
